/**
 * Alipay.com Inc.
 * Copyright (c) 2004-2014 All Rights Reserved.
 */
package com.h2o3.carmack.config;

import org.glassfish.grizzly.websockets.OptimizedBroadcaster;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import com.google.common.base.Objects;
import com.h2o3.carmack.message.MessageDispatcher;
import com.h2o3.carmack.message.json.JsonMessageFactory;
import com.h2o3.carmack.message.json.JsonMessageSerializer;
import com.h2o3.carmack.network.CarmackServer;
import com.h2o3.carmack.network.CarmackWebSocketApplication;

/**
 * @author chensheng
 * @version $Id: ServerBeanDefinitionParser.java, v 0.1 2/10/14 3:37 AM chensheng Exp $
 */
public class ServerBeanDefinitionParser implements BeanDefinitionParser {

    private static final String PATH                   = "path";
    private static final String PORT                   = "port";
    private static final String WEB_SOCKET_APPLICATION = "webSocketApplication";
    private static final String BROADCASTER            = "broadcaster";
    private static final String MESSAGE_DISPATCHER     = "messageDispatcher";
    private static final String MESSAGE_FORMAT         = "messageFormat";
    private static final String MESSAGE_FACTORY        = "messageFactory";
    private static final String MESSAGE_SERIALIZER     = "messageSerializer";

    @Override
    public AbstractBeanDefinition parse(Element element, ParserContext parserContext) {
        RootBeanDefinition serverBeanDefinition = new RootBeanDefinition(CarmackServer.class);

        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.addPropertyValue(PATH, element.getAttribute(PATH));
        propertyValues.add(PORT, element.getAttribute(PORT));
        propertyValues.add(WEB_SOCKET_APPLICATION,
            createWebSocketApplicationDefinition(element, parserContext));

        serverBeanDefinition.setPropertyValues(propertyValues);

        parserContext.getRegistry().registerBeanDefinition(
            BeanDefinitionReaderUtils.generateBeanName(serverBeanDefinition,
                parserContext.getRegistry()), serverBeanDefinition);

        return serverBeanDefinition;
    }

    private BeanDefinition createWebSocketApplicationDefinition(Element element,
                                                                ParserContext parserContext) {
        BeanDefinition messageDispatcherDef = new RootBeanDefinition(MessageDispatcher.class);
        String messageDispatcherName = BeanDefinitionReaderUtils.generateBeanName(
            messageDispatcherDef, parserContext.getRegistry());
        parserContext.getRegistry().registerBeanDefinition(messageDispatcherName,
            messageDispatcherDef);

        RootBeanDefinition webSocketApplicationDefinition = new RootBeanDefinition(
            CarmackWebSocketApplication.class);

        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.addPropertyValue(BROADCASTER, new RootBeanDefinition(
            OptimizedBroadcaster.class));

        propertyValues.addPropertyValue(MESSAGE_DISPATCHER, new RuntimeBeanReference(
            messageDispatcherName));

        if (Objects.equal(element.getAttribute(MESSAGE_FORMAT), "json")) {
            BeanDefinition jsonMessageFactoryDef = new RootBeanDefinition(JsonMessageFactory.class);
            BeanDefinition jsonMessageSerializerDef = new RootBeanDefinition(
                JsonMessageSerializer.class);

            String jsonMessageFactoryName = BeanDefinitionReaderUtils.generateBeanName(
                jsonMessageFactoryDef, parserContext.getRegistry());
            String jsonMessageSerializerName = BeanDefinitionReaderUtils.generateBeanName(
                jsonMessageSerializerDef, parserContext.getRegistry());

            parserContext.getRegistry().registerBeanDefinition(jsonMessageFactoryName,
                jsonMessageFactoryDef);
            parserContext.getRegistry().registerBeanDefinition(jsonMessageSerializerName,
                jsonMessageSerializerDef);

            propertyValues.addPropertyValue(MESSAGE_FACTORY, new RuntimeBeanReference(
                jsonMessageFactoryName));
            propertyValues.addPropertyValue(MESSAGE_SERIALIZER, new RuntimeBeanReference(
                jsonMessageSerializerName));
        } else {
            throw new UnsupportedOperationException("messageFormat "
                                                    + element.getAttribute("messageFormat")
                                                    + " is not supported");
        }

        webSocketApplicationDefinition.setPropertyValues(propertyValues);

        return webSocketApplicationDefinition;
    }
}
